/* Copyright 2010 John L. Reilly

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */

package com.riq;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.riq.entity.Alert;
import com.riq.entity.Department;
import com.riq.entity.Member;
import com.riq.entity.Metric;
import com.riq.entity.Tracking;

@SuppressWarnings("serial")
public class AdminMetricsServlet<cookieValue> extends HttpServlet {
  private static final Logger log = Logger.getLogger(Department.class.getName());
  
  private static final int MAX_COOKIE_AGE_MS = 60*60*24*1000;  // for cookie age
  private Long deptId;  
  private Double metric1;
  private Double metric2;
  private Double metric3;
  private Double metric4;
  private Double metric5;
  private Double metric6;


  PersistenceManager pm = PMF.get().getPersistenceManager();

  @Override
  public void doPost(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException { 
    doGet(request, response);
  }

  @Override
  public void doGet(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {

    // ---------------------------------------------------------------------------------------------
    //  HEADER
    // ---------------------------------------------------------------------------------------------

	deptId = Long.valueOf(request.getParameter("deptId"));
    String action = request.getParameter("action"); 

    // ---------------------------------------------------------------------------------------------
    //  METHOD DIRECTORY
    // ---------------------------------------------------------------------------------------------

    if ("initReading".equalsIgnoreCase(action)) {
      initReading(response, request); 
    } else if ("lastReading".equalsIgnoreCase(action)) {
        lastReading(response, request);
    } else { response.sendRedirect("mainMenu.html"); }
  }

  
  private void initReading(HttpServletResponse response, ServletRequest request) {
    
    // TODO make this a map instead....
    ArrayList<String> metrics = new ArrayList<String>();
    
    if (metric1() != null) { metrics.add(String.valueOf(metric1())); } 
      else { metrics.add(""); }
    if (metric2() != null) { metrics.add(String.valueOf(metric2())); } 
      else { metrics.add(""); }
    if (metric3() != null) { metrics.add(String.valueOf(metric3())); } 
      else { metrics.add(""); }
    if (metric4() != null) { metrics.add(String.valueOf(metric4())); } 
      else { metrics.add(""); }
    if (metric5() != null) { metrics.add(String.valueOf(metric5())); } 
      else { metrics.add(""); }
    if (metric6() != null) { metrics.add(String.valueOf(metric6())); } 
	  else { metrics.add(""); }
   
    Metric m = new Metric(
            deptId,
            System.currentTimeMillis(),
            metrics
    );
  
    pm.makePersistent(m);

    
  }
  
  
  private void lastReading(HttpServletResponse response, ServletRequest request) {

    // last metric
    String queryMetrics = "select from " + Metric.class.getName() + 
    " where deptId == " + deptId + " order by timeStamp desc";
    List<Metric> metrics = (List<Metric>) pm.newQuery(queryMetrics).execute();  
    request.setAttribute("metric", metrics.get(0));
   
    RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/deptMetrics.jsp");
    try {
      dispatcher.forward(request, response);
    } catch (ServletException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    
  }
  
  
  // Percentage of members using Latitude
  private Double metric2() {

    String query = "select from " + Member.class.getName() + 
    " where deptId == " + deptId + " order by lastName";
    List<Member> members = (List<Member>) pm.newQuery(query).execute();  
    
    Double noLatitude = 0.0;
    for (Member m: members) {
      if (m.getlatitudeId().isEmpty()) { noLatitude = noLatitude + 1.0; }
    }

    Double latitudeYes = members.size() - noLatitude;
    Double result = (double) (latitudeYes/members.size() * 100);
   
    return result;
    
  } 
  
  
  // Percentage of members not using Latitude
  private Double metric1() {
    
    String queryMembers = "select from " + Member.class.getName() + 
    " where deptId == " + deptId + " order by lastName";
    List<Member> members = (List<Member>) pm.newQuery(queryMembers).execute();  
    
    Double noLatitude = 0.0;
    for (Member m: members) {
      if (m.getlatitudeId().isEmpty()) { noLatitude = noLatitude + 1.0; }
    }
    Double result = (double) (noLatitude / members.size() * 100);

    return result;
    
  } 
  

  // Percentage of members with fresh (within last 24hrs) Latitude readings
  private Double metric3() {
    
    String query = "select from " + Member.class.getName() + 
    " where deptId == " + deptId + " order by lastName";
    List<Member> members = (List<Member>) pm.newQuery(query).execute();  
    
    Double latitudeFresh = 0.0;
    for (Member m: members) {
      if (m.getdistTimeStamp() > (System.currentTimeMillis() - 
              (24 * 60 * 60 * 1000))) { 
    	  latitudeFresh = latitudeFresh + 1.0; 
      }
    }

    Double sizeDouble = Double.valueOf(members.size());
    Double result = (double) (latitudeFresh / sizeDouble * 100);
    
    return result;
    
  } 
  
  // Percentage of members that used system for the last Alert
  private Double metric4() {
    
    // alerts
    String queryAlert = "select from " + Alert.class.getName() + 
    " where deptId == " + deptId + " order by timeStamp desc";
    List<Alert> alerts = (List<Alert>) pm.newQuery(queryAlert).execute();  
    Alert lastA = alerts.get(0);
    log.info("alert4 qty: " + alerts.size());
    
    // members
    String queryMembers = "select from " + Member.class.getName() + 
    " where deptId == " + deptId + " order by id";
    List<Member> members = (List<Member>) pm.newQuery(queryMembers).execute();  
    log.info("members4 qty: " + members.size());
    
    // tracks
    String queryTracks = "select from " + Tracking.class.getName() + 
    " where alertId == " + lastA.getid() + " order by typeId ";
    List<Tracking> tracks = (List<Tracking>) pm.newQuery(queryTracks).execute(members);
    log.info("tracks4 qty: " + tracks.size());
    
    int memberIncidentUsageCounter = 0;
    Long tempMemberId;
    for (Member m : members) {
      for (Tracking t : tracks ) {
        if (m.getid().equals(t.gettypeId())) {
          memberIncidentUsageCounter++;
          tempMemberId = t.gettypeId();
        }
      }
    }
    Double result = (double) (memberIncidentUsageCounter / members.size());
    
    return result;
    
  }
  
  
// Moving Average (last five alerts) percentage of members using system
  private Double metric5() {

	    // alerts
	    String queryAlert = "select from " + Alert.class.getName() + 
	    " where deptId == " + deptId + " order by timeStamp desc";
	    List<Alert> alerts = (List<Alert>) pm.newQuery(queryAlert).execute();  
	    int alertCount = alerts.size();
	    
	    List<Alert> lastTenAlerts = new ArrayList<Alert>();
	    if (alertCount > 4) {
	    	lastTenAlerts = (List<Alert>) alerts.subList(alertCount - 5, alertCount);
	    } else {
	    	lastTenAlerts = alerts;
	    }

	    ArrayList<Long> alertIds = new ArrayList<Long>();
	    for (Alert a : lastTenAlerts) {
	    	alertIds.add(a.getid());
	    }
	    
	    // members
	    String queryMembers = "select from " + Member.class.getName() + 
	    " where deptId == " + deptId + " order by id";
	    List<Member> members = (List<Member>) pm.newQuery(queryMembers).execute();  
	    
	    // tracks
	    Query qT = pm.newQuery(Tracking.class, " :p.contains(deptId) && type == 'member' ");
	    qT.setOrdering("alertId asc");
	    List<Tracking> tracks = (List<Tracking>) pm.newQuery(qT).execute(alertIds);
	        
	    Double memberIncidentUsageCounter = 0.0;
	    Long tempMemberId = Long.valueOf("9999999");
	    for (Tracking t : tracks ) {
	      if (!tempMemberId.equals(t.gettypeId())) {
	        memberIncidentUsageCounter = memberIncidentUsageCounter + 1.0;
	        tempMemberId = t.gettypeId();
	      }
	    }
	    Double result = memberIncidentUsageCounter / members.size() * 100;
	    
	    return result;
    
  } 
  
  
  // Moving Average (last ten alerts) tracks per alert
  private Double metric6() {

	    // alerts
	    String queryAlert = "select from " + Alert.class.getName() + 
	    " where deptId == " + deptId + " order by timeStamp desc";
	    List<Alert> alerts = (List<Alert>) pm.newQuery(queryAlert).execute();  
	    int alertCount = alerts.size();
	    
	    List<Alert> lastTenAlerts = new ArrayList<Alert>();
	    if (alertCount > 9) {
	    	lastTenAlerts = (List<Alert>) alerts.subList(alertCount - 10, alertCount);
	    } else {
	    	lastTenAlerts = alerts;
	    }

	    ArrayList<Long> alertIds = new ArrayList<Long>();
	    for (Alert a : lastTenAlerts) {
	    	alertIds.add(a.getid());
	    }
	    
	    // members
	    String queryMembers = "select from " + Member.class.getName() + 
	    " where deptId == " + deptId + " order by id";
	    List<Member> members = (List<Member>) pm.newQuery(queryMembers).execute();  
	    
	    // tracks
	    Query qT = pm.newQuery(Tracking.class, " :p.contains(deptId)");
	    qT.setOrdering("alertId asc");
	    List<Tracking> tracks = (List<Tracking>) pm.newQuery(qT).execute(alertIds);
	        
    Double result = (double) (tracks.size()/lastTenAlerts.size());
   
    return result;
    
  } 
  
  

  
  
}
